        TITL DAI FIRMWARE 2E5FC-2E7FB  V1.0  Rev.1
        ORG   :E5FC
*
*
*
*******************************
* INITIALISE HEADER / TRAILER *
*******************************
*
* Sets up 4 background colour lines which can act
* as header/trailer. Sets up colours in colour RAM.
* The header/trailer area consists of 4 groups of
* 4 bytes: 00 00 xx 3x, in which xx is the colour
* and 3x the mode word:
*        x=6: Header.
*        x=F: Trailer.
*        x=0: Middle area (split mode).
*
* Entry: HL: 1st byte header/trailer area.
*        DE: Address table with required colours.
*        A : Screen mode.
*        B : Depth -1 in scans of each blanking
*            line: 06 (header), 0F (trailer),
*            00 (middle).
* Exit:  HL: Points after header/trailer area.
*        AFBCDE preserved.
*
SSUBL   PUSH  PSW
        PUSH  B
        PUSH  D
        MOV   C,A       Store screen mode in C
        MOV   A,B
        ORI   :30       Set 4 colour to make mode
 REM word + rept.count
        PUSH  PSW       Save mode word on stack
        MVI   B,:00
        MOV   A,E       Get lobyte addr colours
        SUI   :7C
        JZ    :E61E     If char mode then 4 colours
        MOV   A,C       Get screen mode
        RAR
        RAR
        MOV   C,B
        JC    :E61F     Jump if 4-colour mode
 REM
* 16-colour modes only:
 REM
        POP   PSW       Restore header/trailer info
        ORI   :80       Set 16-colour (msb=1)
        PUSH  PSW
        LDAX  D         Get colour
        ADD   A         )
        ADD   A         ) Move lonibble into
        ADD   A         ) hinibble
        ADD   A         )
        MVI   B,:FF     Set all foreground
SBL10   MOV   C,A       Colour in C
 REM
* Load header/trailer:
 REM
SBL20   POP   PSW       Get mode word
        PUSH  PSW
        MOV   M,A       Load 1st byte pointer
        DCX   H         Next addr in block
        LDAX  D         Get colour info
        INX   D
        MOV   M,A       Load 2nd byte
        DCX   H         Next addr in block
        MOV   M,B       Load 3rd byte
        DCX   H
        MOV   M,C       Load 4th byte
        DCX   H
        CPI   :B0       All blocks done ?
        JC    :E61F     Next one if not
        POP   PSW
        POP   D
        POP   B
        POP   PSW
        RET
*
*****************************
* SET UP A 4-LINE TEXT AREA *
*****************************
*
* Locates the last few lines of text on the
* screen. If the screen was in split mode, the
* whole contents of the old screen is located.
* If it was mode 0, the last few lines above
* and the cursor line are located.
* The text is then moved to a required position,
* including the cursor, etc.
*
* Entry: HL: Points to address where the text to
*            be put.
* Exit:  HL: Points to new top of text.
*        AFBCDE preserved.
*
SMVTXT  PUSH  PSW
        PUSH  B
        PUSH  D
        MOV   B,H       ) New top of text in BC
        MOV   C,L       )
        LHLD  :009B     Get previous start char
        PUSH  H         on stack
        XCHG            and in DE
        LXI   H,:FDE8   Length split screen char
 REM area
        DAD   D         Calc 1st line mode byte
 REM outside screen frame
        XCHG            in DE
        LHLD  :0072     Get cursor pos addr
        CALL  :E6FB     Check if cursor is still
 REM inside frame
        JC    :E675     Jump if not
        XCHG            HL is addr 1st line mode
 REM outside screen frame
        POP   D         DE is prev start char
SMV10   PUSH  H         Save end preserved text area
        LHLD  :0072     Get cursor pos addr
        CALL  :E36B     Delete cursor
        XTHL            Previous start char in HL
        CALL  :E6C2     Roll screen area to new top
 REM of text; cursor on last line
        XTHL            Cursor pos in HL
        CALL  :E6F2     Calc cursor pos against new
 REM frame start
        DAD   B         Calc new cursor pos addr
        CALL  :E330     Keep cursor on same pos on
 REM line
        LHLD  :0078     Get old start line pointer
        CALL  :E6F2     HL=HL-DE
        DAD   B         Calc new cursor pos
        CALL  :E698     Store addr line mode byte
 REM current line and last addr
 REM on that line
        POP   H         Get end preserved text area
        CALL  :E6F2     HL=HL-DE
        DAD   B
        POP   D
        POP   B
        POP   PSW
        RET
 REM
* Scroll frame 1 line if cursor outside frame:
 REM
SMV20   POP   H
        LHLD  :0078     Get startaddr cursor line
        LXI   D,:FF7A
        DAD   D         HL: start line after cursor
        PUSH  H
        LXI   D,:0218
        DAD   D         Subtract 4 lines and get
        XCHG            line mode byte in DE
        POP   H         Get end reqd area
        JMP   :E64F
*
*********************************
* PLACE CURSOR AT BEGIN OF LINE *
*********************************
*
* Sets the cursor at the beginning of a line.
* Several pointers are updated.
*
* SSETC: Given a pointer to the start of line,
*        sets start and end line variables and
*        places the cursor at the beginning of
*        the line.
* SSETL: Sets only start and end line positions.
*
* Entry: HL: Address line mode byte current line.
* Exit:  ABCDEHL preserved.
*
SSETC   PUSH  PSW
        PUSH  D
        PUSH  H
        LXI   D,:FFF8
        DAD   D         Get addr 1st data byte
 REM on current line
        CALL  :E330     Put cursor on screen
        XRA   A
        STA   :007B     No extended lines
        POP   H
        POP   D
        POP   PSW
SSETL   PUSH  PSW
        SHLD  :0078     Store addr line mode byte
 REM current line
        MVI   A,:80     ) Calc lobyte last addr
        ADD   L         ) on this line
        STA   :007A     Store it in LNEND
        POP   PSW
        RET
*
************************
* SET GRAPHICS COLOURS *
************************
*
* Sets the colours available in a 4 colour mode
* and the initial background in a 16 colour mode.
*
* Entry: HL: Points to colours vector.
* Exit:  All registers preserved.
*
SCOLG   PUSH  PSW
        PUSH  B
        PUSH  D
        PUSH  H
        LXI   D,:009E   Addr 1st COLORG byte
        CALL  :E254     Set COLORG parameters
        LDA   :009D     Get current screen mode
        ORA   A         Check mode type
        LHLD  :0082     Get addr after header
        CP    :E267     If not mode 0: Load COLORG
 REM parameters in header
        RAR             Check if char mode
        LHLD  :008E     Get addr after trailer
        CNC   :E267     If all graphics mode:
 REM Load colours in trailer
SGC10   JMP   :E138     Popall, ret
*
********************
* MOVE SCREEN AREA *
********************
*
* Moves a block of screen data from any position
* to any other.
*
* Entry: BC: Points to highaddress target area.
*        DE: Points to highaddress source area.
*        HL: Points to lowaddress -1 source area.
* Exit:  All registers preserved.
*
MOVES   PUSH  PSW
        PUSH  B
        PUSH  D
        PUSH  H
        CALL  :E6F2     Calc length of block
 REM (neg.value)
        MOV   A,E
        SUB   C
        MOV   A,D
        SBB   B
        JC    :E6E2     Jump if move up
 REM
* Move down:
 REM
        MOV   D,H       ) Length in DE
        MOV   E,L       )
        DAD   B         HL = lowest targetaddr -1
        POP   B         BC = lowest sourceaddr -1
        PUSH  B
MVS10   MOV   A,D
        ORA   E
        JZ    :E6EF     Abort if ready
        INX   D
        INX   H
        INX   B
        LDAX  B         Get byte from source area
        MOV   M,A       and move it into target area
        JMP   :E6D5     Next one
 REM
* Move up:
 REM
MVS20   MOV   A,H
        ORA   L
        JZ    :E6EF     Quit if ready
        INX   H
        LDAX  D         Get byte from source area
        STAX  B         Move it into target area
        DCX   B
        DCX   D
        JMP   :E6E2     Next one
*
MVS40   JMP   :E138     Popall, ret
*
****************
* HL = HL - DE *
****************
*
* Entry: None.
* Exit:  HL=HL-DE.
*        Other registers preserved.
*
SUBDE   PUSH  PSW
        MOV   A,L
        SUB   E
        MOV   L,A       L=L-E
        MOV   A,H
        SBB   D
        MOV   H,A       H=H-D
        POP   PSW
        RET
*
*******************
* COMPARE HL - DE *
*******************
*
* Compares HL with DE (HL-DE).
*
* Exit: Z=0: Not identical:
*            CY=0: DE < HL.
*            CY=1: DE > HL.
*       Z=1: Identical.
*       AF corrupted, BCDEHL preserved.
*
COMP    MOV   A,H
        SUB   D
        RNZ
        MOV   A,L
        SUB   E
        RET
*
*************************
* ADD OFFSET TO ADDRESS *
*************************
*
* Sets HL = HL + A.
*
* Entry: HL: baseaddress.
*        A : offset.
* Exit:  HL = HL + A.
*        BCDE preserved.
*
DADA    ADD   L         Add lobyte addr to offset
        MOV   L,A       and store it in L
        RNC
        INR   H         Incr hibyte if overflow
        RET
*
**********************************
* TWO COMPLEMENT OF 16-BITS DATA *
**********************************
*
* Sets HL = - HL.
*
* Entry: Data to be complemented in HL.
* Exit:  HL contains two-complement.
*        AFBCDE preserved.
*
CMPHL   PUSH  PSW
        MOV   A,L
        CMA             Compl. L
        MOV   L,A       and store it
        MOV   A,H
        CMA             Compl. H
        MOV   H,A       and store it
        INX   H         Add 1
        POP   PSW
        RET
*
****************************
* DRAW A DOT ON THE SCREEN *
****************************
*
* Draws a single blob of a colour anywhere
* on the screen.
*
* Entry: C,HL: Y,X coordinate of the dot.
*        A:    Colour of the dot.
* Exit:  CY=0: O.K.
*        CY=1: Error code in A.
*        ABCDEHL preserved.
*
SDOT    ORA   A
        PUSH  PSW
        PUSH  B
        PUSH  D
        PUSH  H
        MOV   B,C       Y-coord in B
        MOV   D,H       ) X-coord in DE
        MOV   E,L       )
        JMP   :E81D     Into 'SFILL'
*
*****************************
* DRAW A LINE ON THE SCREEN *
*****************************
*
* Draws a line in a given colour between two
* arbitrary points on the screen.
*
* The coordinates are given inclusively. The
* line will be drawn starting at the left end,
* whichever order the parameters are given in.
*
* Entry: B,DE: Y,X coordinate of one end of the
*              line.
*        C,HL: Idem of the other end.
*        A:    Colour of the line.
* Exit:  CY=0: O.K.
*        CY=1: Errorcode in A.
*        ABCDEHL preserved.
*
SDRAW   ORA   A
        PUSH  PSW
        PUSH  B
        PUSH  D
        PUSH  H
        CALL  :E83A     Check arguments, set colour
        PUSH  PSW
        CALL  :E6FB     Check direction of line
        MVI   A,:00     Set 'no X,Y swop'
        JNC   :E72E     Jump if X > Y
 REM
* Swop X,Y:
 REM
        XCHG            Exchange X coordinates
        CMA
*
DRL30   STA   :00C0     FF if X,Y swop, else 00
        MOV   A,C
        ANI   :07
        MOV   D,A       Offset in field in D
        POP   PSW       Get Y-pos left end
        PUSH  H         Save X length
        CALL  :EBB9     Pntr to start of line in
 REM screen RAM
        XTHL
        PUSH  D         Save offset
        PUSH  H         Save DX
        CALL  :E706     HL = - DX
        XTHL
        PUSH  H         Save DX
        MOV   L,E
        MVI   H,:00
        DAD   H
        SHLD  :00B9     Store 2*DY (adj long
 REM sectors)
        MOV   A,E       DY in A
        STA   :00BD     Set count of sectors (1-256)
        POP   H
        CALL  :EB60     HL = DX / DY
        SHLD  :00BB     SECT is INT(DX/DY)
        POP   B         Get -DX
        PUSH  H         Save SECT
        MOV   A,E       
        CALL  :EB46     HL = SECT*DY
        DAD   B         HL = SECT*DY-DX
        DAD   H         HL = 2*(SECT*DY-DX)
        SHLD  :00B5     Store amount to add into
 REM count
        POP   H         Get SECT
        MOV   A,H
        RAR
        MOV   A,L
        RAR             A=INT(SECT/2)
        STA   :00BE     Store amount to trim off
 REM last sector
        INR   A
        MOV   L,A
        MVI   H,:00     HL = INIT
        PUSH  H
        DAD   H         HL = 2*INIT
        MOV   A,E
        CALL  :EB46     HL = 2*INIT*DY
        DAD   B         HL = 2*INIT*DY-DX
        SHLD  :00B7     Set INIT running total
        POP   H         Get length 1st sector
        POP   PSW
        MOV   C,A       C is initial offset
        MOV   A,E
        ORA   A
        JNZ   :E784     If more than 1 sector
        STA   :00BE     Store amount to trim off
 REM last sector
        LHLD  :00BB     Get lower of 2 possible
 REM sectors
        INX   H         Prig length if only 1 sector
DRL40   LXI   D,:00BD   Addr of nr of sectors
        LDAX  D         Get count of sectors
        SUI   :01       -1
        STAX  D         Store it again
        JNC   :E797     Jump if not last sector
 REM
* Trim off last sector:
 REM
        LDA   :00BE     Get amount to trim off
 REM last sector
        CMA
        MOV   E,A
        MVI   D,:FF
        INX   D
        DAD   D
*
DRL50   LXI   D,:0001   Init Y-size is 1
        LDA   :00C0     ) Check if swop X,Y dir.
        ORA   A         ) (line > 45 degrees)
        JZ    :E7A2     Jump if not
        XCHG            Swop X,Y direction
DRL60   MOV   B,E       Get Y-size in B
        XCHG            X-size in DE
        POP   H         Get memory pointer
        DCR   B
        LDA   :00BF     ) Check for Y-invert
        ORA   A         )
        PUSH  PSW       Save condition
        CNZ   :E7FC     Move pntr to bottom of
 REM sector
        DCX   D         Interfacing
        CALL  :EAF7     Draw next sector of line
        INX   D         ) Re-instate real values
        INR   B         )
        POP   PSW       Get earlier condition
        JZ    :E7BA     Jump if no Y-invert
        MVI   B,:01     Init 1 blob down only
DRL80   CALL  :E7FC     Move ptr up/down
        MOV   A,C       Get offset
        ADD   E         Add X-movement
        MOV   C,A       ) Save result
        MOV   B,A       )
        ANI   :07
        CMP   C
        JZ    :E7D2     Jump if not new field
 REM
* If new field:
 REM
        MOV   C,A       Update offset
        MOV   A,B       Get complement new offset
        XRA   C         Clip bits 0,1,2 off
        RAR             )
        RAR             )
        CMA             ) Update pointer
        MOV   E,A       ) to new field
        MVI   D,:FF     )
        INX   D         )
        DAD   D         )
*
DRL83   PUSH  H         Save memory pointer
        LHLD  :00B5     Get amount to add into count
        XCHG            in DE
        LHLD  :00B7     Get count running total
        DAD   D         Add up
        XCHG            Result in DE
        LHLD  :00BB     Get lowest of 2 possible
 REM sectors
        XCHG            in DE (distance to go)
        MOV   A,H
        ORA   A
        JP    :E7ED     Jump if short sector
 REM
* If long sector:
 REM
        INX   D         Go one blob further
        PUSH  D
        XCHG
        LHLD  :00B9     Get adjustment for long
 REM sectors
        DAD   D         Adjust error term
        POP   D
DRL86   SHLD  :00B7     Update running total
        XCHG
        LDA   :00BD     Get nr of sectors
        INR   A
        JNZ   :E784     Next sector if not ready
 REM
* If ready:
 REM
        POP   H
        JMP   :E138     Popall, ret
*
*
*
        END
